﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;

using Microsoft.Xna.Framework;

using SpaceAdventureLib.Universe;
using SpaceAdventureLib.Universe.Units;

namespace SpaceAdventureLib.Universe.Weapons
{
    [Serializable]
    public abstract class Weapon : Collidable
    {

        #region "Properties"

        private Unit fighter = null;
        public Unit Fighter
        {
            get { return this.fighter; }
            set { this.fighter = value; }
        }

        private int capacity = int.MaxValue;
        public int Capacity
        {
            get { return this.capacity; }
            set { this.capacity = value; }
        }

        private int ammoCount = 0;
        public int AmmoCount
        {
            get { return this.ammoCount; }
            set
            { 
                this.ammoCount = value;
                if (this.ammoCount > this.capacity) { this.ammoCount = this.capacity; }
            }
        }

        public bool IsEmpty
        {
            get { return (this.ammoCount == 0); }
        }
                
        private float ammoRate = 10;
        public float AmmoGenRate
        {
            get { return this.ammoRate; }
            set 
            { 
                this.ammoRate = (value > 0) ? value : 1;
                this.interval = 1 / this.ammoRate;
            }
        }

        private bool unlimitedAmmo = false;
        public bool UnlimitedAmmo
        {
            get { return this.unlimitedAmmo; }
            set { this.unlimitedAmmo = value; }
        }

        private bool isShooting = false;
        public bool IsShooting
        {
            get { return this.isShooting; }
        }

        private Vector3 locOffset = Vector3.Zero;
        public Vector3 LocationOffset
        {
            get { return this.locOffset; }
            set { this.locOffset = value; }
        }

        #endregion

        #region "Variables"

        private float interval = 10;
        private float counter = 0;
        private bool shootingActive = false;
        private bool releaseAmmo = true;

        #endregion

        #region "Constructor"

        public Weapon(Fighter fighter)
        {
            this.fighter = fighter;
            this.PreInitialize(fighter.Space);            
        }

        #endregion

        #region "Abstract Methods"

        protected abstract Ammo GenerateAmmo();

        #endregion

        #region "Methods"

        protected override void PreInitialize(Space space)
        {
            base.PreInitialize(space);
        }

        public override void  Update(GameTime gameTime)
        {

 	        if (this.shootingActive)
            {

                float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;

                this.counter += dt;

                if (this.counter > this.interval) 
                { 
                    if (this.isShooting)
                    {
                        this.releaseAmmo = true;
                        this.counter -= interval;
                    }
                    else
                    {
                        this.counter = 0;
                        this.shootingActive = false;
                    }
                
                }

            }

        }

        public void StopShooting()
        {
            this.isShooting = false; ;
        }

        public virtual bool Shoot(Collidable c)
        {
            return this.Shoot(c.Location);
        }

        public virtual bool Shoot(Vector3 destination)
        {

            if (this.IsEmpty && !this.unlimitedAmmo) { return false; }

            this.shootingActive = true;
            this.isShooting = true;
            
            if (this.releaseAmmo)
            {
                this.releaseAmmo = false;
                Ammo a = this.GetNewAmmo(destination); // automatically added to the list of ammos in space
            }

            return true;

        }

        public void Reload()
        {
            this.Reload(this.capacity);
        }

        public void Reload(int amount)
        {
            this.ammoCount += amount;
        }

        private Ammo GetNewAmmo(Vector3 destination)
        {

            Vector3 loc = this.fighter.Location + this.locOffset;
            Vector3 dir = destination - loc;
            dir.Normalize();

            Ammo a = this.GenerateAmmo();
            a.RotateTo(dir);
            a.MoveTo(loc);
            a.Velocity = a.Velocity.Length() * dir;
            a.Activate();
            this.fighter.Space.Ammo.Add(a);

            this.ammoCount--;
            if (this.ammoCount < 0) { this.ammoCount = 0; }

            return a;

        }
        
        #endregion

    }
}
